package com.dctp.ems.utils;

import com.dctp.common.cache.UserCache;
import com.dctp.common.utils.StringUtil;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * OpsLogUtil - 操作日志工具（扩展）
 * 提供：
 *  - save(...)              : 基础保存（若已存在请保留）
 *  - saveChangesAndSave(...) : 根据 old/new 自动生成 changes remark 并保存
 *  - buildChanges(...)      : 仅生成变化描述（返回 String）
 *  - clearColumnCommentCache(...)
 */
public class OpsLogUtil {

    // 缓存：schema.table -> (column -> comment)
    private static final Map<String, Map<String, String>> columnCommentCache = new ConcurrentHashMap<>();

    // 敏感字段关键字（包含任意包含该关键字的列名都会脱敏）
    private static final List<String> SENSITIVE_KEYWORDS = Arrays.asList("password", "pwd", "secret", "token", "card", "bank", "ssn");

    // 默认 remark 最大长度（根据表字段长度设置，示例 128）
    private static final int DEFAULT_MAX_REMARK_LEN = 128;

    private static final Map<String,Map<String,String>> colFormatCache = new ConcurrentHashMap<>();
    public static void init() {
        //格式roleId
        List<Record> roleList = Db.find("select id,name from dctp_role");
        Map<String, String> roleMap = roleList.stream()
                .collect(Collectors.toMap(
                        r -> r.getStr("id"),
                        r -> r.getStr("name")
                ));
        colFormatCache.put("role_id", roleMap);

        //格式化auditStatus
        Map<String,String> auditStatusMap = new HashMap<>();
        auditStatusMap.put("0","待审核");
        auditStatusMap.put("1","审核通过");
        auditStatusMap.put("2","审核不通过");
        colFormatCache.put("audit_status",auditStatusMap);


        //格式化status
        Map<String,String> statusMap = new HashMap<>();
        statusMap.put("0","冻结");
        statusMap.put("1","正常");
        colFormatCache.put("status",statusMap);
    }


    public static String formatCol(String colName,String colValue) {
        if (colName.equals("user_id") || colName.equals("parent_id")) {
            Record user = UserCache.getShowInfo(Long.parseLong(colValue));
            return user.getStr("email");
        }
        Map<String,String> map = colFormatCache.get(colName);
        if (map == null) {
            return colValue;
        }
        return map.get(colValue);
    }


    /**
     * 基础保存（如果你已有相同方法请保留原实现）
     */
    public static void save(Long adminId, String username, String module, String action, String remark,Long userId) {
        Record r = new Record();
        Record admin = Db.findById("card_enterprise_admin", adminId);
        if (null == admin) {
            return;
        }
        if (admin.getInt("is_hidden") == 1) {
            return;
        }

        r.set("admin_id", adminId);
        r.set("username", username == null ? "" : username);
        r.set("module", module == null ? "" : module);
        r.set("action", action == null ? "" : action);
        r.set("remark", remark == null ? "" : remark);
        r.set("user_id", userId);
        Db.save("dctp_ops_log", r);
    }

    /**
     * 根据表、oldRecord 与 newRecord 生成变更 remark 并保存到 dctp_ops_log。
     *
     * @param adminId  操作人ID
     * @param username 操作人用户名
     * @param module   模块名
     * @param action   操作名
     * @param table    数据库表名，支持 "schema.table" 或 "table"
     * @param oldRec   数据库原纪录（Record），如果为 null 则只会尝试记录 newRec 的简略说明
     * @param newRec   新的字段（Record），通常来自 jsonBody() 或 request 参数（必填）
     */
    public static void saveChangesAndSave(Set<String> allowedFields,Long adminId, String username, String module, String action,
                                          String table, Record oldRec, Record newRec) {

        Long userId = "dctp_user".equals(table) ? oldRec.getLong("id") : oldRec.getLong("user_id");
        try {
            String changes = buildChanges(allowedFields,table, oldRec, newRec);
            if (StringUtil.isNotEmpty(changes)) {
                // 截断 remark
                if (changes.length() > DEFAULT_MAX_REMARK_LEN) {
                    changes = changes.substring(0, DEFAULT_MAX_REMARK_LEN - 3) + "...";
                }
                save(adminId, username, module, action, changes,userId);
            }
        } catch (Exception e) {
            // 日志工具不要抛异常影响业务
            e.printStackTrace();
            // 最少记录一条基本日志
            save(adminId, username, module, action, "执行 " + action,userId);
        }
    }

    /**
     * 仅生成变更描述文本（不写日志）。
     * 格式示例： "邮箱: a***@x.com → b***@y.com; 昵称: old → new"
     *
     * @param table  表名（用于读取列注释）
     * @param oldRec 原记录（可为 null）
     * @param newRec 新记录（必需，通常来自 jsonBody()）
     * @return 变更描述字符串（可能为空）
     */
    public static String buildChanges(Set<String> allowedFields,String table, Record oldRec, Record newRec) {

        if (newRec == null) return "";

        // 过滤掉 null 或空 body
        Set<String> newCols = new HashSet<>(
                newRec.getColumnNames() == null
                        ? Collections.emptyList()
                        : Arrays.asList(newRec.getColumnNames())
        );
        if (newCols.isEmpty()) return "";

        Map<String, String> colComments = getColumnComments(table);
        List<String> changes = new ArrayList<>();

        for (String col : newCols) {

            if (!allowedFields.isEmpty() && !allowedFields.contains(col)) {
                continue; // 只关心 fields 指定的字段
            }

            Object newValObj = newRec.get(col);
            Object oldValObj = oldRec == null ? null : oldRec.get(col);

            String oldStr = oldValObj == null ? "" : String.valueOf(oldValObj);
            String newStr = newValObj == null ? "" : String.valueOf(newValObj);

            // 两者相等则跳过
            if (Objects.equals(oldStr, newStr)) continue;

            //格式化
            oldStr = formatCol(col,oldStr);
            newStr = formatCol(col,newStr);

            String label = colComments.getOrDefault(col, col);
            String safeOld = safeTruncate(maskSensitive(col, oldStr), 80);
            String safeNew = safeTruncate(maskSensitive(col, newStr), 80);

            String remark = label + ": " + safeOld + " → " + safeNew;
            if ("balance".equals(col) || "balance2".equals(col)) {
                remark += "，增减：" + newRec.getBigDecimal("amount").toPlainString();
            }
            changes.add(remark);
        }

        return String.join("\n ", changes);
    }

    /**
     * 获取表列注释映射（缓存）。table 支持 "schema.table" 或 "table" 两种形式。
     */
    public static Map<String, String> getColumnComments(String table) {
        if (table == null || table.trim().isEmpty()) {
            return Collections.emptyMap();
        }
        String key = table.trim().toLowerCase();
        if (columnCommentCache.containsKey(key)) {
            return columnCommentCache.get(key);
        }

        Map<String, String> map = new HashMap<>();
        try {
            String schema = null;
            String tableName = key;
            if (key.contains(".")) {
                String[] parts = key.split("\\.", 2);
                schema = parts[0];
                tableName = parts[1];
            }
            if (schema == null || schema.isEmpty()) {
                schema = Db.queryStr("select database()");
            }

            String sql = "SELECT COLUMN_NAME, COLUMN_COMMENT FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?";
            List<Record> cols = Db.find(sql, schema, tableName);
            for (Record c : cols) {
                String col = c.getStr("COLUMN_NAME");
                String comment = c.getStr("COLUMN_COMMENT");
                if (comment == null) comment = "";
                // 如果注释为空则使用列名
                map.put(col, comment.isEmpty() ? col : comment);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        columnCommentCache.put(key, map);
        return map;
    }

    /**
     * 清理列注释缓存。传 null 则清空所有缓存。
     */
    public static void clearColumnCommentCache(String tableOrSchema) {
        if (tableOrSchema == null || tableOrSchema.trim().isEmpty()) {
            columnCommentCache.clear();
            return;
        }
        columnCommentCache.remove(tableOrSchema.trim().toLowerCase());
    }

    // -------------------- 辅助方法 --------------------

    private static String safeTruncate(String s, int maxLen) {
        if (s == null) return "";
        if (s.length() <= maxLen) return s;
        return s.substring(0, maxLen - 3) + "...";
    }

    private static String maskSensitive(String column, String val) {
        if (val == null) return "";
        if (column == null) return val;

        String low = column.toLowerCase();
        for (String k : SENSITIVE_KEYWORDS) {
            if (low.contains(k)) {
                // 简单掩码逻辑，按类型处理
                if (k.equals("email") || low.contains("email")) {
                    return maskEmail(val);
                }
                // 默认为星号
                return "***";
            }
        }

        // 额外规则：email/phone常见命名
        if (low.contains("email")) return maskEmail(val);
        if (low.contains("phone") || low.contains("mobile")) return maskPhone(val);

        return val;
    }

    private static String maskEmail(String email) {
        if (email == null || !email.contains("@")) return email;
        int at = email.indexOf('@');
        if (at <= 1) return "***" + email.substring(at);
        return email.charAt(0) + "***" + email.substring(at);
    }

    private static String maskPhone(String phone) {
        if (phone == null || phone.length() < 7) return phone;
        return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
    }
}
